import os
import yaml
import re

def to_snake_case(name):
    """将文件名转换为snake_case，并处理特殊字符和数字开头"""
    name = re.sub(r'[^a-zA-Z0-9_]+', '_', name) # 替换非字母数字下划线为下划线
    name = re.sub(r'([A-Z]+)([A-Z][a-z])', r'\1_\2', name)
    name = re.sub(r'([a-z\d])([A-Z])', r'\1_\2', name)
    name = name.replace('-', '_').replace('.', '_').replace('@', '_').replace(' ', '_')
    name = re.sub(r'_{2,}', '_', name) # 替换连续下划线
    name = name.strip('_')
    
    # 确保不以数字开头，如果以数字开头，加前缀
    if name and name[0].isdigit():
        name = '_' + name 
        
    return name.lower()

def update_pubspec_assets(project_root='.', assets_dir='assets/images', pubspec_path='pubspec.yaml', dart_output_dir='lib/gen', dart_file_name='app_images.dart'):
    """
    扫描指定目录下的图片文件，更新 pubspec.yaml 中的 Flutter 资产路径，
    并生成一个包含图片资源常量路径的 Dart 类文件。

    Args:
        project_root (str): Flutter 项目的根目录。
        assets_dir (str): 图片资产相对于项目根目录的路径。
        pubspec_path (str): pubspec.yaml 文件相对于项目根目录的路径。
        dart_output_dir (str): 生成 Dart 文件的目标目录，相对于 project_root。
        dart_file_name (str): 生成的 Dart 文件名。
    """
    full_assets_dir = os.path.join(project_root, assets_dir)
    full_pubspec_path = os.path.join(project_root, pubspec_path)
    full_dart_output_path = os.path.join(project_root, dart_output_dir, dart_file_name)

    if not os.path.exists(full_assets_dir):
        print(f"错误: 资产目录 '{full_assets_dir}' 不存在。")
        return

    if not os.path.exists(full_pubspec_path):
        print(f"错误: pubspec.yaml 文件 '{full_pubspec_path}' 不存在。")
        return

    # 确保 Dart 输出目录存在
    os.makedirs(os.path.dirname(full_dart_output_path), exist_ok=True)

    image_extensions = ('.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp')
    new_asset_paths = []
    dart_constants = {}

    print(f"正在扫描 '{full_assets_dir}' 目录下的图片文件...")
    for root, _, files in os.walk(full_assets_dir):
        for file in files:
            if file.lower().endswith(image_extensions):
                relative_path = os.path.relpath(os.path.join(root, file), project_root)
                formatted_path = relative_path.replace('\\', '/')
                new_asset_paths.append(formatted_path)

                # 生成 Dart 常量名
                file_name_without_ext = os.path.splitext(file)[0]
                constant_name = to_snake_case(file_name_without_ext).upper() # 大写常亮名

                # 确保常量名唯一，如果重复则添加计数后缀
                original_constant_name = constant_name
                counter = 1
                while constant_name in dart_constants:
                    constant_name = f"{original_constant_name}_{counter}"
                    counter += 1
                
                dart_constants[constant_name] = formatted_path

    print(f"找到 {len(new_asset_paths)} 个图片资产。")

    # 更新 pubspec.yaml
    try:
        with open(full_pubspec_path, 'r', encoding='utf-8') as f:
            pubspec_content = yaml.safe_load(f)

        if pubspec_content is None:
            pubspec_content = {}

        if 'flutter' not in pubspec_content:
            pubspec_content['flutter'] = {}

        if 'assets' not in pubspec_content['flutter'] or not isinstance(pubspec_content['flutter']['assets'], list):
            pubspec_content['flutter']['assets'] = []

        existing_assets = pubspec_content['flutter']['assets']
        updated_assets = []

        # 保留所有旧的非资产路径 (例如目录形式的声明 'assets/')
        for asset in existing_assets:
            if asset.strip().endswith('/') or not asset.strip().lower().endswith(image_extensions):
                updated_assets.append(asset)
        
        # 添加新的图片资产，避免重复
        for new_path in sorted(new_asset_paths): # 排序以保持一致性
            if new_path not in updated_assets:
                updated_assets.append(new_path)
        
        pubspec_content['flutter']['assets'] = updated_assets

        with open(full_pubspec_path, 'w', encoding='utf-8') as f:
            yaml.dump(pubspec_content, f, sort_keys=False, default_flow_style=False, indent=2, allow_unicode=True)

        print(f"成功更新 '{pubspec_path}' 中的 Flutter 资产。")

    except yaml.YAMLError as e:
        print(f"解析或写入 pubspec.yaml 错误: {e}")
    except Exception as e:
        print(f"发生未知错误: {e}")

    # 生成 Dart 文件
    try:
        dart_file_content = """// ignore_for_file: non_constant_identifier_names

class AppImages { // 这个类现在直接包含所有图片常量
"""
        # 对常量名进行排序，以便生成的 Dart 文件内容一致
        sorted_constant_names = sorted(dart_constants.keys())
        for constant_name in sorted_constant_names:
            path = dart_constants[constant_name]
            # <--- 关键修改：注释改为 AppImages.CONSTANT_NAME
            dart_file_content += f"""  /// AppImages.{constant_name}
  static const String {constant_name} = '{path}'; 
"""
            dart_file_content += "\n" # 在每个常量定义后添加一个空行
            
        # 移除 AppAssets 类
        # dart_file_content += """}
        # 
        # class AppAssets {
        #   const AppAssets._(); 
        # 
        #   static final AppImages image = AppImages(); 
        # }
        # """
        dart_file_content += "}" # 结束 AppImages 类定义


        with open(full_dart_output_path, 'w', encoding='utf-8') as f:
            f.write(dart_file_content)
        print(f"成功生成 '{full_dart_output_path}' 文件。")
    except Exception as e:
        print(f"生成 Dart 文件错误: {e}")


if __name__ == "__main__":
    update_pubspec_assets(
        project_root='.',
        assets_dir='assets/images',
        dart_output_dir='lib/gen',
        dart_file_name='app_images.dart'
    )